import Entity from './entity';
import Global from './settings';
import { ResManager } from './custom/ResManager';
import { import_folder, addToGroups, changePos, getTime, changeToList, rectInflate } from './support';
import SoundManager from './custom/SoundManger';
// Learn TypeScript:
//  - https://docs.cocos.com/creator/manual/en/scripting/typescript.html
// Learn Attribute:
//  - https://docs.cocos.com/creator/manual/en/scripting/reference/attributes.html
// Learn life-cycle callbacks:
//  - https://docs.cocos.com/creator/manual/en/scripting/life-cycle-callbacks.html


export default class Enemy extends Entity {

    sprite_type 
    status 
    image : cc.Node
    animations 
    monster_name
    monster_info

    health
    exp
    speed
    attack_damage
    resistance
    attack_radius
    notice_radius
    attack_type

    can_attack
    attack_time
    attack_cooldown
    damage_player
    trigger_death_particles
    add_exp

    vulnerable
    hit_time
    invincibility_duration

    death_sound
    hit_sound
    attack_sound

    constructor(monster_name,pos,groups,obstacle_sprites,damage_player,trigger_death_particles,add_exp) {
        super(groups)

        this.sprite_type = 'enemy'

        pos = changePos(pos)

		// graphics setup
		this.import_graphics(monster_name)
		this.status = 'idle'

		// movement
		this.obstacle_sprites = obstacle_sprites

		// stats
		this.monster_name = monster_name
		let monster_info = Global.monster_data[this.monster_name]
		this.health = monster_info['health']
		this.exp = monster_info['exp']
		this.speed = monster_info['speed'] / 5
		this.attack_damage = monster_info['damage']
		this.resistance = monster_info['resistance']
		this.attack_radius = monster_info['attack_radius']
		this.notice_radius = monster_info['notice_radius']
		this.attack_type = monster_info['attack_type']

		// player interaction
		this.can_attack = true
		this.attack_time = null
		this.attack_cooldown = 400
		this.damage_player = damage_player
		this.trigger_death_particles = trigger_death_particles
		this.add_exp = add_exp

		// invincibility timer
		this.vulnerable = true
		this.hit_time = null
		this.invincibility_duration = 300

        let node = this
        let sp = node.addComponent(cc.Sprite)
        sp.spriteFrame = this.animations[this.status][this.frame_index]
        let width = sp.spriteFrame.getTexture().width
        let height = sp.spriteFrame.getTexture().height
        // @ts-ignore
        node.script = this
        this.image = this

        
        this.image.setPosition(pos[0]+width/2, pos[1]-height/2)

        this.rect = this.image.getBoundingBox()
        this.hitbox = rectInflate(this.rect, 0, -10)

		// sounds
		this.death_sound = "death"
		this.hit_sound = "hit"
		this.attack_sound = monster_info["attack_sound"]

        this.animation_speed = 0.015

        addToGroups(this.image, groups)

    }

	import_graphics(name) {
        this.animations = {'idle':[],'move':[],'attack':[]}

        let res = ResManager.getInstance().getRes()

        for(let animKey in this.animations) {
            let searchKey = name + "-" + animKey
            this.animations[animKey] = res[searchKey]
        }
    }

    get_player_distance_direction(player) {
        let enemy_vec = this.rect.center
		let player_vec = player.rect.center
		let distance = player_vec.sub(enemy_vec).mag()

        let direction = cc.v2(0,0)
		if(distance > 0){
			direction = player_vec.sub(enemy_vec).normalize()
        }
		return [distance,direction]
    }

    get_status(player) {
        let distance = this.get_player_distance_direction(player)[0]

		if(distance <= this.attack_radius && this.can_attack){
			if(this.status != 'attack') {
				this.frame_index = 0
            }
			this.status = 'attack'
		} else if(distance <= this.notice_radius) {
			this.status = 'move'
        } else {
			this.status = 'idle'
        }
    }

    actions(player) {
        if(this.status == 'attack') {
            this.attack_time = getTime()
            this.damage_player(this.attack_damage,this.attack_type, this.attack_sound)
        } else if(this.status == 'move') {
            this.direction = this.get_player_distance_direction(player)[1]
            
        } else {
            this.direction = cc.v2(0, 0)
        }
    }

    animate() {
        let animation = this.animations[this.status]
        
        let animLen = changeToList(animation).length

		this.frame_index += this.animation_speed
		if(this.frame_index >= animLen){
			if(this.status == 'attack'){
				this.can_attack = false
            }
			this.frame_index = 0
        }
        
        let sprite = this.image.getComponent(cc.Sprite)
		sprite.spriteFrame = animation[Math.floor(this.frame_index)]
		this.rect = this.image.getBoundingBox()

		if(!this.vulnerable){
			let alpha = this.wave_value()
			this.image.opacity = alpha
        } else {
			this.image.opacity = 255
        }
    }

    cooldowns() {
        let current_time = getTime()
		if(!this.can_attack){ 
			if(current_time - this.attack_time >= this.attack_cooldown){ 
				this.can_attack = true
            }
        }

		if(!this.vulnerable){ 
			if(current_time - this.hit_time >= this.invincibility_duration){ 
				this.vulnerable = true
            }
        }
    }

    get_damage(player,attack_type) {
		if(this.vulnerable) {
            SoundManager.getInstance().playEffect(this.hit_sound)
			this.direction = this.get_player_distance_direction(player)[1]
			if(attack_type == 'weapon') {
				this.health -= player.get_full_weapon_damage()
            } else {
				this.health -= player.get_full_magic_damage()
            }
            this.hit_time = getTime()
			this.vulnerable = false
        }
    }

    check_death() {
        if(this.health <= 0) {
            this.kill()
            this.trigger_death_particles([this.rect.center.x, this.rect.center.y],this.monster_name)
            this.add_exp(this.exp)
			SoundManager.getInstance().playEffect(this.death_sound)
        }
    }

    hit_reaction() {
        if(!this.vulnerable) {
            this.direction = this.direction.mul(-this.resistance)
        }
    }

    update(dt: any): void {
        this.hit_reaction()
        
		this.move(this.speed)
		this.animate()
		this.cooldowns()
		this.check_death()
    }

    move(speed) {
        // this.direction = cc.v2(0, 0)
        super.move(speed)
        this.setPosition(this.rect.center)
    }

    enemy_update(player) {
        this.get_status(player)
		this.actions(player)
    }


}
